package com.mia.craftstudio.utils;

import com.sun.imageio.plugins.png.PNGImageReader;
import gnu.trove.map.TDoubleFloatMap;
import gnu.trove.map.hash.TDoubleFloatHashMap;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageReader;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;

public class ImageIOCS {
   private static final IIORegistry theRegistry = IIORegistry.getDefaultInstance();
   private static final ImageReader pngReader = new PNGImageReader((ImageReaderSpi)null);
   private static final int[] mipmapBuffer = new int[4];
   static float[] cachedPow22ComponentValue = new float[256];
   static TDoubleFloatMap cachedPow045 = new TDoubleFloatHashMap();

   public static BufferedImage read(InputStream input) throws IOException {
      ImageInputStream stream = new MemoryCacheImageInputStream(input);
      pngReader.setInput(stream, true, true);
      BufferedImage bi = pngReader.read(0, pngReader.getDefaultReadParam());
      pngReader.dispose();
      stream.close();
      return bi;
   }

   public static int[][] generateMipmapData(int mipmapLevels, int textureWidth, int[][] inImages) {
      int[][] outImages = new int[mipmapLevels + 1][];
      outImages[0] = inImages[0];
      if (mipmapLevels > 0) {
         boolean isTransparent = false;

         int level;
         for(level = 0; level < inImages.length; ++level) {
            if (inImages[0][level] >> 24 == 0) {
               isTransparent = true;
               break;
            }
         }

         for(level = 1; level <= mipmapLevels; ++level) {
            if (inImages[level] != null) {
               outImages[level] = inImages[level];
            } else {
               int[] previousLevelImage = outImages[level - 1];
               int[] newCurrentLevelImage = new int[previousLevelImage.length >> 2];
               int currentLevelTextureWidth = textureWidth >> level;
               int currentLevelTextureHeight = newCurrentLevelImage.length / currentLevelTextureWidth;
               int previousLevelTextureWidth = currentLevelTextureWidth << 1;

               for(int x = 0; x < currentLevelTextureWidth; ++x) {
                  for(int y = 0; y < currentLevelTextureHeight; ++y) {
                     int i2 = 2 * (x + y * previousLevelTextureWidth);
                     newCurrentLevelImage[x + y * currentLevelTextureWidth] = blendColors(previousLevelImage[i2 + 0], previousLevelImage[i2 + 1], previousLevelImage[i2 + 0 + previousLevelTextureWidth], previousLevelImage[i2 + 1 + previousLevelTextureWidth], isTransparent);
                  }
               }

               outImages[level] = newCurrentLevelImage;
            }
         }
      }

      return outImages;
   }

   private static int blendColors(int pixel1, int pixel2, int pixel3, int pixel4, boolean isTransparent) {
      if (!isTransparent) {
         return blendColorComponent(pixel1, pixel2, pixel3, pixel4, 24) << 24 | blendColorComponent(pixel1, pixel2, pixel3, pixel4, 16) << 16 | blendColorComponent(pixel1, pixel2, pixel3, pixel4, 8) << 8 | blendColorComponent(pixel1, pixel2, pixel3, pixel4, 0);
      } else {
         mipmapBuffer[0] = pixel1;
         mipmapBuffer[1] = pixel2;
         mipmapBuffer[2] = pixel3;
         mipmapBuffer[3] = pixel4;
         float alphaComponent = 0.0F;
         float redComponent = 0.0F;
         float greenComponent = 0.0F;
         float blueComponent = 0.0F;

         int alphaValue;
         for(alphaValue = 0; alphaValue < 4; ++alphaValue) {
            if (mipmapBuffer[alphaValue] >> 24 != 0) {
               alphaComponent += cachedPow22ComponentValue[mipmapBuffer[alphaValue] >> 24 & 255];
               redComponent += cachedPow22ComponentValue[mipmapBuffer[alphaValue] >> 16 & 255];
               greenComponent += cachedPow22ComponentValue[mipmapBuffer[alphaValue] >> 8 & 255];
               blueComponent += cachedPow22ComponentValue[mipmapBuffer[alphaValue] >> 0 & 255];
            }
         }

         alphaValue = (int)((double)fastPow045((double)(alphaComponent * 0.25F)) * 255.0D);
         int redValue = (int)((double)fastPow045((double)(redComponent * 0.25F)) * 255.0D);
         int greenValue = (int)(fastPow045((double)(greenComponent * 0.25F)) * 255.0F);
         int blueValue = (int)(fastPow045((double)(blueComponent * 0.25F)) * 255.0F);
         if (alphaValue < 96) {
            alphaValue = 0;
         }

         return alphaValue << 24 | redValue << 16 | greenValue << 8 | blueValue;
      }
   }

   private static int blendColorComponent(int pixel1, int pixel2, int pixel3, int pixel4, int componentShift) {
      return (int)(fastPow045((double)((cachedPow22ComponentValue[pixel1 >> componentShift & 255] + cachedPow22ComponentValue[pixel2 >> componentShift & 255] + cachedPow22ComponentValue[pixel3 >> componentShift & 255] + cachedPow22ComponentValue[pixel4 >> componentShift & 255]) * 0.25F)) * 255.0F);
   }

   private static float fastPow045(double val) {
      if (!cachedPow045.containsKey(val)) {
         cachedPow045.put(val, (float)FastMath.pow(val, 0.45454545454545453D));
      }

      return cachedPow045.get(val);
   }

   static {
      for(int i = 0; i < 256; ++i) {
         cachedPow22ComponentValue[i] = (float)FastMath.pow((double)((float)i / 255.0F), 2.2D);
      }

   }
}
